home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / program / 619 / lachck / lacheck.src / lacheck.lex < prev    next >
Encoding:
Text File  |  1992-07-17  |  17.3 KB  |  856 lines

  1. %{ 
  2. /*                    -*- Mode: C -*- 
  3.  * 
  4.  * lacheck.lex - A consistency checker checker for LaTeX documents
  5.  * 
  6.  * Copyright (C) 1991 Kresten Krab Thorup (krab@iesd.auc.dk).
  7.  * 
  8.  * $Locker: krab $
  9.  * $Revision: 1.15 $
  10.  * Author          : Kresten Krab Thorup
  11.  * Created On      : Sun May 26 18:11:58 1991
  12.  * Last Modified By: Kresten Krab Thorup
  13.  * Last Modified On: Sat Jun  6 16:40:19 1992
  14.  * Update Count    : 51
  15.  * 
  16.  * HISTORY
  17.  * 6-Jun-1992        Kresten Krab Thorup    
  18.  *    Last Modified: Sat Jun  6 16:37:44 1992 #48 (Kresten Krab Thorup)
  19.  *    Added test for whitespace before punctation mark
  20.  * 17-Dec-1991  (Last Mod: Tue Dec 17 21:01:24 1991 #41)  Kresten Krab Thorup
  21.  *    Added 'word word` and missing ~ before cite and ref
  22.  * 18-Jun-1991  (Last Mod: Tue Jun 18 19:20:43 1991 #17)  Kresten Krab Thorup
  23.  *    Added check (or rather management) for \newenvironment and
  24.  *    \newcommand - as suggested by Per Abrahamsen abrham@hugin.dk
  25.  * 30-May-1991  (Last Mod: Thu May 30 02:22:33 1991 #15)  Kresten Krab Thorup
  26.  *    Added check for `$${punct}' and `{punct}$' constructions
  27.  * 30-May-1991  (Last Mod: Wed May 29 10:31:35 1991 #6)  Kresten Krab Thorup
  28.  *    Improved (dynamic) stack management from Andreas Stolcke ...
  29.  *                                       <stolcke@ICSI.Berkeley.EDU> 
  30.  * 26-May-1991  Kresten Krab Thorup
  31.  *    Initial distribution version.
  32.  */
  33.  
  34. /* * Last edited: Jun  6 16:40 1992 (krab) */
  35.  
  36. #include <stdio.h>
  37. #include <string.h>
  38. #include <sys/param.h>
  39.  
  40. /* extern char *realloc(); */ /* mj - don't declare - this is in headers */
  41.  
  42. #ifdef NEED_STRSTR
  43. char *strstr(char *, char*);  /* mj - provide prototype in case if needed */
  44. #endif
  45.  
  46. #define GROUP_STACK_SIZE 10
  47. #define INPUT_STACK_SIZE 10
  48.  
  49. #define PROGNAME "LaCheck"
  50.  
  51.   /* macros */
  52.  
  53. #define CG_NAME gstack[gstackp-1].s_name
  54. #define CG_TYPE gstack[gstackp-1].s_type
  55. #define CG_LINE gstack[gstackp-1].s_line
  56. #define CG_FILE gstack[gstackp-1].s_file
  57.  
  58. char *bg_command();
  59. void pop();
  60. void push();
  61. void g_checkend();
  62. void e_checkend();
  63. void f_checkend();
  64. void input_file();
  65. void print_bad_match();
  66. int check_top_level_end();
  67.  
  68.   /* global variables */
  69.  
  70. char returnval[100];
  71. int line_count = 1;
  72. int warn_count = 0;
  73. char *file_name;
  74. char verb_char;
  75.  
  76.   /* the group stack */
  77.  
  78. typedef struct tex_group 
  79.  {
  80.     unsigned char *s_name;
  81.     int s_type;
  82.     int s_line;
  83.     char *s_file; 
  84.  } tex_group;
  85.  
  86. tex_group *gstack;
  87. int gstack_size = GROUP_STACK_SIZE;
  88. int gstackp = 0;
  89.  
  90. typedef struct input_ 
  91.  {
  92.     YY_BUFFER_STATE stream;
  93.     char *name;
  94.     int linenum;
  95.  } input_;
  96.  
  97. input_ *istack;
  98. int istack_size = INPUT_STACK_SIZE;
  99. int istackp = 0;
  100.  
  101. int def_count = 0;
  102.  
  103. %}
  104.  
  105. %x B_ENVIRONMENT E_ENVIRONMENT VERBATIM INCLUDE MATH COMMENT VERB DEF
  106. %x AFTER_DISPLAY ENV_DEF
  107.  
  108. b_group ("{"|\\bgroup)
  109. e_group ("}"|\\egroup)
  110.  
  111. b_math \\\(
  112. e_math \\\)
  113. math \$
  114.  
  115. b_display \\\[
  116. e_display \\\]
  117. display \$\$
  118.  
  119. non_par_ws ([ \t]+\n?[ \t]*|[ \t]*\n[ \t]*|[ \t]*\n?[ \t]+)
  120.  
  121. ws [ \n\t]
  122. space ({ws}|\~|\\space)
  123. hard_space (\~|\\space)
  124.  
  125. u_letter [A-Zהןד] 
  126. l_letter [a-zµ°σ] 
  127. punct [\!\.\?]
  128. atoz [a-zA-Z]
  129. letter (u_letter|l_letter)
  130.  
  131. c_bin ("-"|"+"|"\\cdot"|"\\oplus"|"\\otimes"|"\\times")
  132. l_bin (",")
  133.  
  134. general_abbrev {letter}+{punct}
  135.  
  136. non_abbrev {u_letter}{u_letter}+{punct}
  137.  
  138. font_spec (rm|bf|sl|it|tt|em|mediumseries|normalshape)
  139.  
  140. primitive \\(above|advance|catcode|chardef|closein|closeout|copy|count|countdef|cr|crcr|csname|delcode|dimendef|dimen|divide|expandafter|font|hskp|vskip|openout)
  141.  
  142. symbol ("$"("\\"{atoz}+|.)"$"|"\\#"|"\\$"|"\\%"|"\\ref")
  143.  
  144. %%
  145.  
  146. "\\\\" { ; }
  147.  
  148. <ENV_DEF,DEF,INITIAL>"\\\%" { ; }
  149.  
  150. <ENV_DEF,DEF,INITIAL>"%"[^\n]* { ; }
  151.  
  152. <ENV_DEF,DEF,INITIAL>\n     { line_count++; }
  153.  
  154. <ENV_DEF,DEF,INITIAL>"\\\{" { ; }
  155.  
  156. <ENV_DEF,DEF,INITIAL>"\\\}" { ; }
  157.  
  158. "\\\$" { ; }
  159.  
  160. {b_group} {  push( "{", 0, line_count);}
  161.  
  162. {e_group} {  g_checkend(0); }
  163.  
  164. "\\"[exg]?(def|newcommand)[^\{]+     BEGIN(DEF);
  165.  
  166.  
  167. <DEF>{b_group} { ++def_count; }
  168.  
  169. <DEF>{e_group} { --def_count;
  170.          if(def_count == 0)
  171.              BEGIN(INITIAL); }
  172.  
  173. <DEF>. { ; }
  174.  
  175. "\\"newenvironment"{"[a-zA-Z]+"}"[^\{]+     BEGIN(ENV_DEF);
  176.  
  177. <ENV_DEF>{b_group} { ++def_count; }
  178.  
  179. <ENV_DEF>{e_group} { --def_count;
  180.          if(def_count == 0)
  181.              BEGIN(DEF); }
  182.  
  183. <ENV_DEF>. { ; }
  184.  
  185. {b_math} {
  186.     if(CG_TYPE == 4 || CG_TYPE == 5)
  187.     print_bad_match(yytext,4);
  188.     else
  189.     {
  190.     push( yytext, 4, line_count);
  191.     }}
  192.  
  193. {e_math} {  g_checkend(4); }
  194.  
  195. {b_display} {
  196.     if(CG_TYPE == 4 || CG_TYPE == 5)
  197.     print_bad_match(yytext,5);
  198.     else 
  199.     {
  200.     push( yytext, 5, line_count);
  201.     }}
  202.  
  203.  
  204. {e_display} {  g_checkend(5);     BEGIN(AFTER_DISPLAY);}
  205.  
  206. <AFTER_DISPLAY>{punct} { 
  207.  
  208.     printf( "\"%s\", line %d: puctation mark \"%s\" should be placed before end of displaymath\n", 
  209.        file_name, line_count, yytext); 
  210.     ++warn_count ; 
  211.  
  212.   BEGIN(INITIAL); }
  213.  
  214. <AFTER_DISPLAY>. {  BEGIN(INITIAL); }
  215.  
  216. <AFTER_DISPLAY>\n {     ++line_count; 
  217.             BEGIN(INITIAL); }
  218.  
  219. {punct}/("\$"|"\\)") { if (CG_TYPE == 4)
  220.        {
  221.      printf( "\"%s\", line %d: puctation mark \"%s\" should be placed after end of math mode\n", 
  222.         file_name, line_count, yytext); 
  223.      ++warn_count ;
  224.        }}
  225.  
  226. {math} {
  227.  
  228.     if(CG_TYPE == 5)
  229.     print_bad_match(yytext, 4);
  230.     else 
  231.  
  232.     if(CG_TYPE == 4)
  233.     {
  234.     e_checkend(4, yytext);
  235.     }
  236.     else
  237.     {
  238.     push( yytext, 4, line_count); 
  239.     }}
  240.  
  241.  
  242. {display}  {
  243.  
  244.     if(CG_TYPE == 4)
  245.     print_bad_match(yytext,5);
  246.     else 
  247.  
  248.     if(CG_TYPE == 5)
  249.     {
  250.     e_checkend(5, yytext);
  251.         BEGIN(AFTER_DISPLAY);
  252.     }
  253.     else
  254.     {
  255.     push( yytext, 5, line_count);
  256.     }}
  257.  
  258. \\begingroup/[^a-zA-Z]  {
  259.  {
  260.     push((unsigned char *)"\\begingroup", 1, line_count); 
  261.  }}
  262.  
  263.  
  264. \\endgroup/[^a-zA-Z]  {
  265.  {
  266.     g_checkend(1);
  267.  }}
  268.  
  269.  
  270. \\begin[ \t]*"{" { BEGIN(B_ENVIRONMENT); }
  271.  
  272. \\begin[ \t]*/\n { 
  273.  {
  274.     
  275.     printf("\"%s\", line %i: {argument} missing for \\begin\n",
  276.        file_name, line_count) ;
  277.     ++warn_count;
  278.  }}
  279.  
  280. <B_ENVIRONMENT>[^\}\n]+ { 
  281.  {
  282.     if (strcmp( yytext, "verbatim" ) == 0 )
  283.     {
  284.      input();
  285.      BEGIN(VERBATIM);
  286.     }
  287.     else
  288.     {
  289.          push(yytext, 2, line_count);
  290.       input();
  291.      BEGIN(INITIAL);
  292.     }
  293.  }}
  294.  
  295. <VERBATIM>\\end[ \t]*\{verbatim\} { BEGIN(INITIAL); }
  296.  
  297. <VERBATIM>\t {
  298.      printf("\"%s\", line %i: TAB character in verbatim environment\n",
  299.        file_name, line_count) ;
  300.     ++warn_count;
  301.  }
  302.  
  303. <VERBATIM>. { ; }
  304.  
  305. <VERBATIM>\n { ++line_count; }
  306.  
  307.  
  308. \\verb.    { 
  309.       sscanf (yytext, "\\verb%c", &verb_char  ); 
  310.       BEGIN(VERB); 
  311.     }
  312.  
  313. <VERB>. {
  314.         if ( *yytext == (unsigned char)verb_char )
  315.           BEGIN(INITIAL); 
  316.         if ( *yytext == '\n' )
  317.            ++line_count;
  318.     } 
  319.  
  320.  
  321. \\end[ \t]*"{" { BEGIN(E_ENVIRONMENT); }
  322.  
  323. \\end[ \t]*/\n { 
  324.  {
  325.     printf("\"%s\", line %i: {argument} missing for \\end\n",
  326.        file_name, line_count) ;
  327.     ++warn_count;
  328.  }}
  329.  
  330.  
  331. <E_ENVIRONMENT>[^\}\n]+ { 
  332.  {
  333.     e_checkend(2, yytext);
  334.     input();
  335.     
  336.     BEGIN(INITIAL);
  337.  }}
  338.  
  339.  
  340. {ws}({letter}".")*{letter}*{l_letter}"."/{non_par_ws}+{l_letter}    { 
  341.  {
  342.     if ( *yytext == '\n' )
  343.         ++line_count; 
  344.  
  345.     printf( "\"%s\", line %d: missing `\\ ' after \"%s\"\n", 
  346.        file_name, line_count, ++yytext); 
  347.     ++warn_count ; 
  348.  }}
  349.  
  350. ({l_letter}".")*{letter}*{l_letter}"."/{non_par_ws}+{l_letter}    { 
  351.  {
  352.     printf( "\"%s\", line %d: missing `\\ ' after \"%s\"\n", 
  353.        file_name, line_count, yytext); 
  354.     ++warn_count ; 
  355.  }}
  356.  
  357. {ws}{non_abbrev}/{non_par_ws}{u_letter}   { 
  358.  {
  359.     if ( *yytext == '\n' )
  360.     ++line_count;
  361.     printf("\"%s\", line %d: missing `\\@' before punctation mark in \"%s\"\n", 
  362.        file_name, line_count, ++yytext); 
  363.     ++warn_count ; 
  364.  }}
  365.  
  366. {non_abbrev}/{non_par_ws}{u_letter}   { 
  367.  {
  368.     printf("\"%s\", line %d: missing `\\@' before `.' in \"%s\"\n", 
  369.        file_name, line_count, yytext); 
  370.     ++warn_count ; 
  371.  }}
  372.  
  373. ({hard_space}{space}|{space}{hard_space})  { 
  374.  
  375.     printf("\"%s\", line %d: double space at \"%s\"\n",
  376.        file_name, line_count, yytext); 
  377.     ++warn_count;
  378.   }
  379.  
  380. {c_bin}{ws}?(\\(\.|\,|\;|\:))*{ws}?\\ldots{ws}?(\\(\.|\,|\;|\:))*{ws}?{c_bin} {
  381.     printf("\"%s\", line %d: \\ldots should be \\cdots in \"%s\"\n",
  382.        file_name, line_count, yytext); 
  383.     ++warn_count;
  384.   }
  385.  
  386. [^\\]{l_bin}{ws}?(\\(\.|\,|\;|\:))*{ws}?\\cdots{ws}?(\\(\.|\,|\;|\:))*{ws}?[^\\]{l_bin} {
  387.     printf("\"%s\", line %d: \\cdots should be \\ldots in \"%s\"\n",
  388.        file_name, line_count, yytext); 
  389.     ++warn_count;
  390.   }
  391.  
  392. {c_bin}{ws}?(\\(\.|\,|\;|\:))*{ws}?"."+{ws}?(\\(\.|\,|\;|\:))*{ws}?{c_bin} {
  393.     printf("\"%s\", line %d: Dots should be \\cdots in \"%s\"\n",
  394.        file_name, line_count, yytext); 
  395.     ++warn_count;
  396.   }
  397.  
  398. [^\\]{l_bin}{ws}?(\\(\.|\,|\;|\:))*{ws}?"."+{ws}?(\\(\.|\,|\;|\:))*{ws}?[^\\]{l_bin} {
  399.     printf("\"%s\", line %d: Dots should be \\ldots in \"%s\"\n",
  400.        file_name, line_count, yytext); 
  401.     ++warn_count;
  402.   }
  403.  
  404.  
  405. \.\.\. { 
  406.     printf("\"%s\", line %d: Dots should be ellipsis \"%s\"\n",
  407.        file_name, line_count, yytext); 
  408.     ++warn_count;
  409.   }
  410.  
  411. {ws}"\\"(ref|cite)"\{"[^\}]+\}  {
  412.  
  413.     printf("\"%s\", line %d: perhaps you should insert a `~' before \"%s\"\n",
  414.        file_name, line_count, ++yytext); 
  415.   }
  416.  
  417.  
  418.  /*
  419.  {primitive}/[^a-zA-Z] {
  420.  {
  421.     printf("\"%s\", line %d: Don't use \"%s\" in LaTeX documents\n", 
  422.        file_name, line_count, yytext); 
  423.     ++warn_count ; 
  424.  }}    
  425.  */
  426.  
  427. \\{font_spec}/[ \t]*"{" { 
  428.  {
  429.     printf("\"%s\", line %d: Fontspecifiers don't take arguments. \"%s\"\n", 
  430.        file_name, line_count, yytext); 
  431.     ++warn_count; 
  432.   /*    (void) input(); */
  433.  }}
  434.  
  435.  
  436. \\([a-zA-Z\@]+\@[a-zA-Z\@]*|[a-zA-Z\@]*\@[a-zA-Z\@]+) { 
  437.  {
  438.     printf("\"%s\", line %d: Do not use @ in LaTeX macro names. \"%s\"\n", 
  439.        file_name, line_count, yytext); 
  440.     ++warn_count; 
  441.  }}
  442.  
  443. " "\'+{letter}+ { 
  444.  {
  445.     printf("\"%s\", line %d: Use ` to begin quotation, not ' \"%s\"\n", 
  446.        file_name, line_count, yytext); 
  447.     ++warn_count; 
  448.  }}
  449.  
  450. {letter}+\` { 
  451.  {
  452.     printf("\"%s\", line %d: Use ' to end quotation, not ` \"%s\"\n", 
  453.        file_name, line_count, yytext); 
  454.     ++warn_count; 
  455.  }}
  456.  
  457.  
  458. {ws}+{punct} { 
  459.  {
  460.     printf("\"%s\", line %d: Whitespace before punctation mark in \"%s\"\n", 
  461.        file_name, line_count, yytext); 
  462.     ++warn_count; 
  463.  }}
  464.  
  465.  
  466. "%"  { BEGIN(COMMENT); }
  467.  
  468. <COMMENT>\n    { BEGIN(INITIAL); ++line_count; }
  469.  
  470. <COMMENT>.    { ; }
  471.  
  472.  
  473. \\(input|include)([ \t]|"{")    { BEGIN(INCLUDE); }
  474.  
  475. <INCLUDE>[^\}\n]+    {
  476.  {
  477.     if ( strstr(yytext,".sty") == NULL )
  478.     {
  479.         input_file(yytext);
  480.     }
  481.     else
  482.     {
  483.         printf("\"%s\", line %d: Style file `%s\' omitted.\n",
  484.             file_name,
  485.             line_count,
  486.             yytext);
  487.         input();
  488.     }
  489.     BEGIN(INITIAL);
  490.  }}
  491.  
  492. <<EOF>> { 
  493.       if (--istackp < 0)
  494.           yyterminate(); 
  495.  
  496.       else
  497.         { 
  498.           fclose(yyin);
  499.             f_checkend(file_name);
  500.           yy_switch_to_buffer(istack[istackp].stream);
  501.           free(file_name);
  502.           line_count = istack[istackp].linenum;
  503.           file_name = istack[istackp].name;
  504.           input();
  505.           BEGIN(INITIAL);
  506.         }        
  507.      
  508.     }
  509.  
  510.  
  511. . { ; }
  512. %%
  513. int main( argc, argv )
  514. int argc;
  515. char *argv[];
  516. {
  517.     /* allocate initial stacks */
  518.     gstack = (tex_group *)malloc(gstack_size * sizeof(tex_group));
  519.     istack = (input_ *)malloc(istack_size * sizeof(input_));
  520.     if ( gstack == NULL || istack == NULL ) {
  521.     fprintf(stderr, "%s: not enough memory for stacks\n", PROGNAME);
  522.     exit(3);
  523.     }
  524.     
  525.     if(argc > 1)
  526.     {
  527.         if ( (file_name = malloc(strlen(argv[1]) + 5)) == NULL ) {
  528.         fprintf(stderr, "%s: out of memory\n", PROGNAME);
  529.         exit(3);
  530.     }
  531.     
  532.     strcpy(file_name, argv[1]);
  533.     
  534.     if ((yyin = fopen( file_name, "r")) != NULL )
  535.     {
  536.         push(file_name, 3, 1);
  537.         yylex();
  538.         f_checkend(file_name);
  539.     }
  540.     else {   
  541.          strcat(file_name, ".tex" );
  542.          if ((yyin = fopen( file_name, "r")) != NULL )
  543.          {
  544.              push(file_name, 3, 1);
  545.              yylex();
  546.              f_checkend(file_name);
  547.          }
  548.          else
  549.              fprintf(stderr,
  550.                 "%s: Could not open : %s\n",PROGNAME, argv[1]);
  551.          }
  552.     }
  553.     else
  554.     {
  555.     printf("\n* %s *\n\n",PROGNAME);
  556.     printf("\t...a consistency checker for LaTeX documents.\n\n");
  557.  
  558.     printf("Usage:\n\tlacheck filename[.tex] <return>\n\n\n");
  559.  
  560.     printf("\tFrom within Emacs:\n\n\t");
  561.     printf("M-x compile <return>\n\tlacheck filename[.tex] <return>");
  562.     printf("\n\n\tUse C-x ` to step through the messages.\n\n");
  563.     printf("\n\tThe found context is displayed in \"double quotes\"\n\n");
  564.     printf("Remark:\n\tAll messages are only warnings!\n\n");
  565.     printf("\tYour document may be right though LaCheck tells\n");
  566.     printf("\tsomething else.\n\n");
  567.     }
  568.     return(0);
  569. }
  570.  
  571. #ifdef NEED_STRSTR
  572. char *
  573. strstr(string, substring)
  574.     register char *string;    /* String to search. */
  575.     char *substring;        /* Substring to try to find in string. */
  576. {
  577.     register char *a, *b;
  578.  
  579.     /* First scan quickly through the two strings looking for a
  580.      * single-character match.  When it's found, then compare the
  581.      * rest of the substring.
  582.      */
  583.  
  584.     b = substring;
  585.     if (*b == 0) {
  586.     return string;
  587.     }
  588.     for ( ; *string != 0; string += 1) {
  589.     if (*string != *b) {
  590.         continue;
  591.     }
  592.     a = string;
  593.     while (1) {
  594.         if (*b == 0) {
  595.         return string;
  596.         }
  597.         if (*a++ != *b++) {
  598.         break;
  599.         }
  600.     }
  601.     b = substring;
  602.     }
  603.     return (char *) 0;
  604. }
  605. #endif /* NEED_STRSTR */
  606.  
  607. void push(p_name, p_type, p_line)
  608. unsigned char *p_name;
  609. int p_type;
  610. int p_line;
  611. {
  612.     if ( gstackp == gstack_size ) {    /* extend stack */
  613.     gstack_size *= 2;
  614.     gstack = (tex_group *)realloc(gstack, gstack_size * sizeof(tex_group));
  615.     if ( gstack == NULL ) {
  616.         fprintf(stderr, "%s: stack out of memory", PROGNAME);
  617.     exit(3);
  618.     }
  619.     }
  620.     
  621.     if ( (gstack[gstackp].s_name =
  622.         (unsigned char *)malloc(strlen(p_name) + 1)) == NULL ||
  623.          (gstack[gstackp].s_file =
  624.         (char *)malloc(strlen(file_name) + 1)) == NULL ) {
  625.     fprintf(stderr, "%s: out of memory\n", PROGNAME);
  626.     exit(3);
  627.     }
  628.  
  629.     strcpy(gstack[gstackp].s_name,p_name);
  630.     gstack[gstackp].s_type = p_type;
  631.     gstack[gstackp].s_line = p_line;    
  632.     strcpy(gstack[gstackp].s_file,file_name);
  633.     ++gstackp;    
  634.  
  635. }
  636.  
  637. void input_file(file_nam)
  638. char *file_nam;
  639. {
  640.     char *tmp_file_name;
  641.     FILE *tmp_yyin;
  642.  
  643.     if ( (tmp_file_name = malloc(strlen(file_nam) + 5)) == NULL ) {
  644.     fprintf(stderr, "%s: out of memory\n", PROGNAME);
  645.     exit(3);
  646.     }
  647.     strcpy(tmp_file_name,file_nam);
  648.  
  649.     if (istackp == istack_size) {    /* extend stack */
  650.     istack_size *= 2;
  651.     istack = (input_ *)realloc(istack, istack_size * sizeof(input_));
  652.     if ( istack == NULL ) {
  653.         fprintf(stderr, "%s: \\input stack out of memory\n", PROGNAME);
  654.     exit(3);
  655.         } 
  656.     } 
  657.         
  658.     istack[istackp].stream = YY_CURRENT_BUFFER;
  659.     istack[istackp].linenum = line_count;
  660.     istack[istackp].name = file_name;
  661.     ++istackp;    
  662.  
  663.     if ((tmp_yyin = fopen( file_nam, "r")) != NULL )
  664.     {
  665.       yyin = tmp_yyin;
  666.       yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE));
  667.       file_name = tmp_file_name;
  668.       push(file_name, 3, 1);
  669.           line_count = 1;
  670.     }
  671.     else {
  672.       (void) strcat(tmp_file_name, ".tex");
  673.       if ((tmp_yyin = fopen( tmp_file_name , "r")) != NULL )
  674.         {
  675.         yyin = tmp_yyin;
  676.            yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE));
  677.         file_name = tmp_file_name;
  678.         push(file_name, 3, 1);
  679.                line_count = 1;
  680.         }
  681.           else
  682.       {
  683.            --istackp;
  684.            fclose(tmp_yyin);
  685.            free(tmp_file_name);
  686.            printf("\"%s\", line %d: Could not open \"%s\"\n", 
  687.             file_name,
  688.             line_count,
  689.             file_nam);
  690.            input();
  691.       }
  692.      }
  693. }
  694.  
  695. void pop()
  696. {
  697.     if ( gstackp == 0 )
  698.     {
  699.            fprintf(stderr, "%s: Stack underflow\n", PROGNAME);
  700.     exit(4);
  701.     }
  702.     --gstackp;
  703.  
  704.     free(gstack[gstackp].s_name);
  705.     free(gstack[gstackp].s_file);
  706. }
  707.  
  708. char *bg_command(name)
  709. char *name;
  710. {
  711.     
  712.     switch (CG_TYPE) {
  713.     
  714.     case 2:
  715.     (void) strcpy( returnval, "\\begin\{" );
  716.     (void) strcat( returnval, (char *) name);
  717.     (void) strcat( returnval, "}" );
  718.     break;
  719.     
  720.     case 3:
  721.     (void) strcpy( returnval, "beginning of file " );
  722.     (void) strcat( returnval, (char *) name);
  723.     break;
  724.     
  725.     case 4:
  726.     (void) strcpy( returnval, "math begin " );
  727.     (void) strcat( returnval, (char *) name);
  728.     break;
  729.     
  730.     case 5:
  731.     (void) strcpy( returnval, "display math begin " );
  732.     (void) strcat( returnval, (char *) name);
  733.     break;
  734.     
  735.     default:
  736.         (void) strcpy( returnval, name );
  737.     
  738.     }
  739.     
  740.     return ((char *)returnval);
  741. }
  742.  
  743. char *eg_command(name,type)
  744. int type;
  745. char *name;
  746. {
  747.     
  748.     switch (type) {
  749.     
  750.     case 2:
  751.     (void) strcpy( returnval, "\\end{" );
  752.     (void) strcat( returnval, (char *) name);
  753.     (void) strcat( returnval, "}" );
  754.     break;
  755.     
  756.     case 3:
  757.     (void) strcpy( returnval, "end of file " );
  758.     (void) strcat( returnval, (char *) name);
  759.     break;
  760.     
  761.     case 4:
  762.     (void) strcpy( returnval, "math end " );
  763.     (void) strcat( returnval, (char *) name);
  764.     break;
  765.     
  766.     case 5:
  767.     (void) strcpy( returnval, "display math end " );
  768.     (void) strcat( returnval, (char *) name);
  769.     break;
  770.     
  771.     default:
  772.         (void) strcpy( returnval, name );
  773.     break;
  774.     }
  775.     
  776.     return ((char *)returnval);
  777. }
  778.  
  779.  
  780. void g_checkend(n)
  781. int n;
  782. {
  783.     if ( check_top_level_end(yytext,n) == 1 ) 
  784.        if (  CG_TYPE != n  )
  785.      print_bad_match(yytext,n);
  786.        else
  787.     pop();
  788. }
  789.  
  790. void e_checkend(n, name)
  791. int n;
  792. char *name;
  793. {
  794.    if ( check_top_level_end(name,n) == 1 )
  795.     {
  796.      if (  CG_TYPE != n  ||  strcmp( CG_NAME, name ) != 0 )
  797.         print_bad_match(name,n);
  798.  
  799.      pop();
  800.  
  801.     }
  802. }
  803.  
  804. void f_checkend(name)
  805. char *name;
  806. {
  807.     if ( check_top_level_end(name,3) == 1 )
  808.      {
  809.        if (  CG_TYPE != 3  ||  strcmp( CG_NAME, name ) != 0 )
  810.  
  811.         while( CG_TYPE != 3  )
  812.     {
  813.       print_bad_match(name,3);
  814.           pop();
  815.         }
  816.  
  817.          pop();  
  818.      }
  819. }
  820.  
  821. void print_bad_match(end_command,type)
  822. char *end_command;          
  823. int type;
  824. {
  825.       printf("\"%s\", line %i: <- unmatched \"%s\"\n",
  826.              file_name, 
  827.          line_count, 
  828.          eg_command( end_command , type) ) ;
  829.  
  830.       printf("\"%s\", line %i: -> unmatched \"%s\"\n",
  831.              CG_FILE, 
  832.          CG_LINE, 
  833.          bg_command( CG_NAME ) ) ;
  834.       warn_count += 2;
  835. }
  836.  
  837. int check_top_level_end(end_command,type)
  838. char *end_command;          
  839. int type;
  840. {
  841.     if ( gstackp == 0 )
  842.     {
  843.      printf("\"%s\", line %i: \"%s\" found at top level\n",
  844.            file_name, 
  845.            line_count, 
  846.            eg_command( end_command, type )) ;
  847.      ++warn_count;
  848.          return(0);
  849.     }
  850.     else
  851.         return(1);
  852. }
  853.  
  854.  
  855.  
  856.